package com.threepure.penpipe.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.threepure.penpipe.R;
import com.threepure.penpipe.pen.BasePen;
import com.threepure.penpipe.pen.Eraser;
import com.threepure.penpipe.pen.Pen;
import com.threepure.penpipe.pen.PenConfig;
import com.threepure.penpipe.util.BitmapUtil;
import com.threepure.penpipe.util.Config;
import com.threepure.penpipe.util.DisplayUtil;
import com.threepure.penpipe.redo.StepOperator;
import com.threepure.penpipe.util.colorpicker.ColorPickerDialog;

/**
 * @author ThreePure
 * @date 2021/11/17 8:40
 * @description: 手写画板视图
 * @since 1.8
 */
public class PaintView extends View{

    private static final String TAG = "TP_PaintView=>";

    public static final int TYPE_PEN    = 0;
    public static final int TYPE_ERASER = 1;

    /**画板宽度*/
    private int paintViewWidth;
    /**画板高度*/
    private int paintViewHeight;
    /**画笔粗细*/
    private int penSize;

    /**Paint类保存有关如何绘制几何图形、文本和位图的样式和颜色信息。*/
    private Paint mPaint;
    /**位图*/
    private Bitmap bitmap;
    /**Canvas类保存“draw”调用。要绘制一些东西，您需要4个基本组件：一个保存像素的位图、一个承载绘制调用（写入位图）的画布、一个绘图原语（例如Rect、Path、text、Bitmap）和一个画图（用于描述绘图的颜色和样式）。*/
    private Canvas mCanvas;

    /**画笔*/
    private BasePen paintPen;
    /**橡皮*/
    private Eraser eraser;
    /**撤销、重做类对象*/
    private StepOperator stepOperation;

    /**
     * 是否允许写字
     */
    private boolean isWriteEnable = true;
    /**
     * 是否橡皮擦模式
     */
    private boolean isEraser = false;
    /**
     * 是否可以撤销
     */
    private boolean isCanUndo;
    /**
     * 是否可以恢复
     */
    private boolean isCanRedo;
    /**
     * 是否有绘制
     */
    private boolean hasDraw = false;
    /**是否正在绘制*/
    private boolean isDrawing = false;

    /**记录手写笔类型：触控笔/手指*/
    private int toolType = 0;

    /**是否有新的动作*/
    private boolean hasNewAction = false;

    /**撤销、重做的接口*/
    private StepCallback mCallback;


    public PaintView(Context context) {
        super(context);
    }

    public PaintView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public PaintView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(bitmap, 0, 0, mPaint);
        if (!isEraser) {
            paintPen.draw(canvas);
        }
        super.onDraw(canvas);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        //当子级不希望此父级及其祖先使用ViewGroup.onInterceptTouchEvent（MotionEvent）拦截触摸事件时调用。
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        toolType = event.getToolType(0);

        if (!isWriteEnable && toolType != MotionEvent.TOOL_TYPE_STYLUS) {
            return false;
        }

        if (isEraser) {
            eraser.onTouchEvent(event, mCanvas);
        } else {
            paintPen.onTouchEvent(event, mCanvas);
        }

        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                isDrawing = false;
                break;
            case MotionEvent.ACTION_MOVE:
                //添加了动作，更新判断
                hasNewAction = true;

                hasDraw = true;
                isCanUndo = true;
                isDrawing = true;
                break;
            case MotionEvent.ACTION_CANCEL:
                isDrawing = false;
                break;
            case MotionEvent.ACTION_UP:
                if (stepOperation != null && isDrawing) {
                    stepOperation.addBitmap(bitmap);
                }
                isCanUndo = !stepOperation.currentIsFirst();
                isCanRedo = !stepOperation.currentIsLast();
                if (mCallback != null) {
                    mCallback.onOperateStatusChanged();
                }
                isDrawing = false;
                break;
            default:
                break;
        }
        invalidate();
        return true;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width  = onMeasureR(0, widthMeasureSpec);
        int height = onMeasureR(1, heightMeasureSpec);
        //onMeasure（int，int）必须调用此方法来存储测量的宽度和测量的高度。否则将在测量时触发异常。
        setMeasuredDimension(width, height);
    }

    /**
     * @description:  初始化画板视图.   [通过这个方法初始化画板尺寸，而非在构造方法中，原因是在使用的时候是在布局文件中]
     * @Param: [int width  画板宽度, int height 画板高度, java.lang.String path   初始图片路径]
     * @Return: void
     */
    public void init(int width, int height, String path) {

        this.paintViewWidth  = width;
        this.paintViewHeight = height;

        bitmap = Bitmap.createBitmap(paintViewWidth, paintViewHeight, Bitmap.Config.ARGB_8888);

        paintPen = new Pen();

        //初始画笔设置
        penSize = DisplayUtil.dip2px(getContext(), Config.PEN_SIZES[PenConfig.PAINT_SIZE_LEVEL]);
        mPaint = new Paint();
        mPaint.setColor(Config.PEN_COLORS[PenConfig.PAINT_COLOR_LEVEL]);
        mPaint.setStrokeWidth(penSize);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setAlpha(0xFF);
        mPaint.setAntiAlias(true);
        mPaint.setStrokeMiter(1.0f);
        paintPen.setPaint(mPaint);


        //初始画布设置
        initCanvas();

        stepOperation = new StepOperator();

        //eraser = new Eraser();

        if (!TextUtils.isEmpty(path)) {
            //将文件路径解码为位图。（将这个位图设置为背景）
            Bitmap bitmap = BitmapFactory.decodeFile(path);
            //图片大小调整适配画布宽高
            resize(bitmap, paintViewWidth, paintViewHeight);
        }else {
            stepOperation.addBitmap(bitmap);
        }
    }

    /**
     * @description: 初始画布设置
     * @Param: []
     * @Return: void
     */
    private void initCanvas() {
        mCanvas = new Canvas(bitmap);
        //设置画布的背景色为透明
        mCanvas.drawColor(Color.TRANSPARENT);

    }

    /**
     * @description: 图片大小调整适配画布宽高
     * @param bitmap  原图
     * @param paintViewWidth   新宽度
     * @param paintViewHeight  新高度
     **/
    private void resize(Bitmap bitmap, int paintViewWidth, int paintViewHeight) {
        if (bitmap != null) {
            if (paintViewWidth >= this.paintViewWidth) {
                paintViewHeight = paintViewWidth * bitmap.getHeight() / bitmap.getWidth();
            }
            this.paintViewWidth = paintViewWidth;
            this.paintViewHeight = paintViewHeight;

            bitmap = Bitmap.createBitmap(paintViewWidth, paintViewHeight, Bitmap.Config.ARGB_8888);
            restoreLastBitmap(bitmap, bitmap);
            initCanvas();
            if (stepOperation != null) {
                stepOperation.addBitmap(bitmap);
            }
            invalidate();
        }
    }

    /**
     * @description:    恢复最后画的bitmap
     * @param srcBitmap 最后的bitmap
     * @param newBitmap 新bitmap
     **/
    private void restoreLastBitmap(Bitmap srcBitmap, Bitmap newBitmap) {

        try {
            if (srcBitmap == null || srcBitmap.isRecycled()) {
                return;
            }
            srcBitmap = BitmapUtil.zoomImg(srcBitmap, newBitmap.getWidth());
            //缩放后如果还是超出新图宽高，继续缩放
            if (srcBitmap.getWidth() > newBitmap.getWidth() || srcBitmap.getHeight() > newBitmap.getHeight()) {
                srcBitmap = BitmapUtil.zoomImage(srcBitmap, newBitmap.getWidth(), newBitmap.getHeight());
            }
            //保存所有的像素的数组，图片宽×高
            int[] pixels = new int[srcBitmap.getWidth() * srcBitmap.getHeight()];
            srcBitmap.getPixels(pixels, 0, srcBitmap.getWidth(), 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight());
            newBitmap.setPixels(pixels, 0, srcBitmap.getWidth(), 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight());
        } catch (OutOfMemoryError e) {
        }
    }

    /**
     * @description: 用于计算控件的高度
     * @param attr   标志位
     * @param oldMeasure
     * @Return: int  控件高度
     **/
    public int onMeasureR(int attr, int oldMeasure) {

        int newSize = 0;
        int mode = MeasureSpec.getMode(oldMeasure);
        int oldSize = MeasureSpec.getSize(oldMeasure);

        switch (mode) {
            case MeasureSpec.EXACTLY:
                newSize = oldSize;
                break;
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED:

                float value = paintViewWidth;

                if (attr == 0) {
                    if (bitmap != null) {
                        value = bitmap.getWidth();
                    }
                    // 控件的宽度
                    newSize = (int) (getPaddingLeft() + value + getPaddingRight());

                } else if (attr == 1) {
                    value = paintViewHeight;
                    if (bitmap != null) {
                        value = bitmap.getHeight();
                    }
                    // 控件的高度
                    newSize = (int) (getPaddingTop() + value + getPaddingBottom());
                }
                break;
            default:
                break;
        }
        return newSize;
    }

    /**
     * @description: 撤销操作
     * @Return: void
     **/
    public void undo() {

        if (stepOperation == null || !isCanUndo) {
            return;
        }
        if (!stepOperation.currentIsFirst()) {
            isCanUndo = true;
            stepOperation.undo(bitmap);
            hasDraw = true;
            invalidate();

            if (stepOperation.currentIsFirst()) {
                isCanUndo = false;
                hasDraw = false;
            }
        } else {
            isCanUndo = false;
            hasDraw = false;
        }
        if (!stepOperation.currentIsLast()) {
            isCanRedo = true;
        }
        if (mCallback != null) {
            mCallback.onOperateStatusChanged();
        }
    }

    /**
     * @description: 恢复操作
     * @Return: void
     **/
    public void redo() {

        if (stepOperation == null || !isCanRedo) {
            return;
        }
        if (!stepOperation.currentIsLast()) {
            isCanRedo = true;
            stepOperation.redo(bitmap);
            hasDraw = true;
            invalidate();
            if (stepOperation.currentIsLast()) {
                isCanRedo = false;
            }
        } else {
            isCanRedo = false;
        }
        if (!stepOperation.currentIsFirst()) {
            isCanUndo = true;
        }
        if (mCallback != null) {
            mCallback.onOperateStatusChanged();
        }
    }

    /**
     * @description: 清除画布，记得清除点的集合
     * @Return: void
     **/
    public void reset() {
        //用指定的颜色填充位图的像素
        bitmap.eraseColor(Color.TRANSPARENT);
        hasDraw = false;
        paintPen.clear();
        if (stepOperation != null) {
            stepOperation.reset();
            stepOperation.addBitmap(bitmap);
        }
        isCanRedo = false;
        isCanUndo = false;
        if (mCallback != null) {
            mCallback.onOperateStatusChanged();
        }
        initCanvas();
        invalidate();
    }

    /**
     * @description: 释放这个PaintVie
     * @Return: void
     **/
    public void release() {
        // TODO: 2021/11/18 过时的方法
        destroyDrawingCache();
        if (bitmap != null) {
            bitmap.recycle();
            bitmap = null;
        }
        if (stepOperation != null) {
            //清空这个回退队列
            stepOperation.freeBitmaps();
            stepOperation = null;
        }
    }

    /**
     * @description:  设置画笔样式
     * @param penType
     * @Return: void
     **/
    public void setPenType(int penType) {

        isEraser = false;
        switch (penType) {
            case TYPE_PEN:
                paintPen = new Pen();
                break;
            case TYPE_ERASER:
                eraser = new Eraser();
                isEraser = true;
                break;
            default:
                break;
        }
        //设置
        if (paintPen.isNullPaint()) {
            paintPen.setPaint(mPaint);
        }
        invalidate();
    }

    /**
     * @description:  设置画笔大小
     * @param width  大小
     * @Return: void
     **/
    public void setPaintWidth(int width) {
        if (mPaint != null) {
            mPaint.setStrokeWidth(DisplayUtil.dip2px(getContext(), width));
            paintPen.setPaint(mPaint);
            invalidate();
        }
    }

    /**
     * @description:  设置画笔颜色
     * @param color  颜色
     * @Return: void
     **/
    public void setPaintColor(int color) {
        if (mPaint != null) {
            mPaint.setColor(color);
            paintPen.setPaint(mPaint);
            invalidate();
        }
    }

    /**
     * @description: mPaintView.clearEraser(width);
     * @param width
     * @Return: void
     **/
    public void newEraser(int width){
        if (eraser!= null){
            eraser = null;
            eraser = new Eraser();
            eraser.setEraserWidth(width);
        }
    }

    /**
     * @description: 构建Bitmap
     * @param isCrop 是否只保存有字迹部分
     * @Return: android.graphics.Bitmap  所绘制的bitmap
     **/
    public Bitmap buildAreaBitmap(boolean isCrop) {

        if (!hasDraw) {
            return null;
        }
        Bitmap result;
        if (isCrop) {
            result = BitmapUtil.clearBlank(bitmap, 50, Color.TRANSPARENT);
        } else {
            result = bitmap;
        }
        destroyDrawingCache();
        return result;
    }

    /**
     * @description: 是否可以写
     * @Return: boolean
     **/
    public boolean isWriteEnable() {
        return isWriteEnable;
    }

    /**
     * @description: 手指是否可写
     * @param fingerEnable
     * @Return: void
     **/
    public void setFingerEnable(boolean fingerEnable) {
        isWriteEnable = fingerEnable;
    }

    /**
     * @description:  是否为橡皮擦模式
     * @Return: boolean
     **/
    public boolean isEraser() {
        return isEraser;
    }

    /**
     * @description: 是否可以撤销
     * @Return: boolean
     **/
    public boolean canUndo() {
        return isCanUndo;
    }

    /**
     * @description: 是否可以恢复
     * @Return: boolean
     **/
    public boolean canRedo() {
        return isCanRedo;
    }

    /**
     * @description: 获得一个bitmap
     * @Return: android.graphics.Bitmap
     **/
    public Bitmap getBitmap() {
        return bitmap;
    }

    public Bitmap getLastBitmap() {
        return bitmap;
    }

    /**
     * @description: 判断是否有绘制内容在画布上
     * @Return: boolean
     **/
    public boolean isEmpty() {
        return !hasDraw;
    }

    /**
     * @description:  是否有更新
     * @Return: boolean
     */
    public boolean isHasNewAction() {
        return hasNewAction;
    }

    /**
     * @description: 设置更新的状态
     * @param hasNewAction
     * @Return: void
     **/
    public void setHasNewAction(boolean hasNewAction) {
        this.hasNewAction = hasNewAction;
    }

    /**
     * @description: 撤销。重做的接口对象
     * @param callback
     * @Return: void
     **/
    public void setStepCallback(StepCallback callback) {
        this.mCallback = callback;
    }

    /**
     * @description: 操作变更
     **/
    public interface StepCallback {
        /**
         * 操作变更
         */
        void onOperateStatusChanged();
    }

}
